package fer

import (
	"fmt"
	"io"
	"sort"
	"strings"
	"time"
	"unicode"
	"unicode/utf8"
)

// 结果
type Rates struct {
	UpdateAt time.Time       `json:"update_at,omitempty" xml:"update_at,omitempty"` // 更新时间
	From     string          `json:"from,omitempty" xml:"from,omitempty"`           // 来源
	Data     map[string]Rate `json:"data,omitempty" xml:"data,omitempty"`           // 汇率数据
	Duration time.Duration   `json:"duration" xml:"duration"`                       // 抓取耗时
}

// 汇率
type Rate struct {
	Name            string  `find:"td:nth-child(1)" json:"name" xml:"name"`                           // 货币名称
	Currency        string  `json:"currency" xml:"currency"`                                          // 货币代号
	BuyingRate      float64 `find:"td:nth-child(2)" json:"buying_rate" xml:"buying_rate"`             // 汇买价
	CashBuyingRate  float64 `find:"td:nth-child(3)" json:"cash_buying_rate" xml:"cash_buying_rate"`   // 钞买价
	SellingRate     float64 `find:"td:nth-child(4)" json:"selling_rate" xml:"selling_rate"`           // 汇卖价
	CashSellingRate float64 `find:"td:nth-child(5)" json:"cash_selling_rate" xml:"cash_selling_rate"` // 钞卖价
	MiddleRate      float64 `find:"td:nth-child(6)" json:"middle_rate" xml:"middle_rate"`             // 中间价
}

func (r Rates) WriteTo(w io.Writer) (n int64, err error) {
	var keys []string
	var l int
	for key, rate := range r.Data {
		keys = append(keys, key)
		if w := countWidth(rate.Name); w > l {
			l = w
		}
	}
	sort.Strings(keys)

	fw := 46 + l
	fmt.Fprintln(w)
	fmt.Fprintf(w, "人民币外汇牌价%*s数据来源:%s\n", fw-countWidth("人民币外汇牌价数据来源:")-countWidth(r.From), "", r.From)
	fmt.Fprintln(w, strings.Repeat("-", fw))
	fmt.Fprintf(w, "货币%*s    汇买    钞买    汇卖    钞卖    折算\n", l+2, "")
	fmt.Fprintln(w, strings.Repeat("-", fw))

	for _, key := range keys {
		rate := r.Data[key]
		fmt.Fprintf(
			w,
			"%s | %*s  %s  %s  %s  %s  %s\n",
			rate.Currency,
			hzCount(rate.Name)-l, rate.Name,
			formatPrice(rate.BuyingRate),
			formatPrice(rate.CashBuyingRate),
			formatPrice(rate.SellingRate),
			formatPrice(rate.CashSellingRate),
			formatPrice(rate.MiddleRate),
		)
	}
	fmt.Fprintln(w, strings.Repeat("-", fw))
	footer := fmt.Sprintf("更新:%s 耗时:%s", r.UpdateAt.Format("2006-01-02 15:04:05"), durationString(r.Duration))
	fmt.Fprintf(w, "%*s\n\n", fw-hzCount(footer), footer)
	return
}

func (r Rates) String() string {
	var w strings.Builder
	_, _ = r.WriteTo(&w)
	return w.String()
}

func (r *Rates) SetDuration(st time.Time) {
	r.Duration = time.Since(st)
}

func durationString(d time.Duration) string {
	s := d.String()
	i := strings.IndexByte(s, '.')
	if i == -1 {
		return s
	}
	var j int
	for j = len(s) - 1; j >= 0; j-- {
		if unicode.IsDigit(rune(s[j])) {
			break
		}
	}
	x := s[i:j]
	if len(x) > 2 {
		x = x[:2]
	}
	return s[:i] + x + s[j:]
}

func formatPrice(price float64) string {
	if price == 0 {
		return strings.Repeat(" ", 5) + "-"
	} else {
		return fmt.Sprintf("%6.2f", price)
	}
}

func hzCount(s string) int {
	return (len(s) - utf8.RuneCountInString(s)) / 2
}

func countWidth(s string) int {
	return (len(s) + utf8.RuneCountInString(s)) / 2
}
